# -*- coding: utf-8 -*-
import base64
import random
from io import BytesIO

from PIL import Image, ImageDraw, ImageFont
from random import choice, randint, randrange
import string

# 候选字符集,大小写字母+数字
chrs = string.ascii_letters + string.digits


def selected_chrs(length):
    """
    返回length个随机字符串
    :param length:
    :return:
    """
    result = ''.join(choice(chrs) for _ in range(length))
    return result


CAPTCHA_MATH_CHALLENGE_OPERATOR = 'x'


def math_challenge():
    operators = ("+", "*", "-")
    operands = (random.randint(1, 10), random.randint(1, 10))
    operator = random.choice(operators)
    if operands[0] < operands[1] and "-" == operator:
        operands = (operands[1], operands[0])
    challenge = "%d%s%d" % (operands[0], operator, operands[1])
    return (
        "{}=".format(challenge.replace("*", CAPTCHA_MATH_CHALLENGE_OPERATOR)),
        str(eval(challenge)),
    )


def get_color():
    """
    设置随机颜色
    :return:
    """
    r = randint(50, 230)
    g = randint(50, 240)
    b = randint(50, 200)
    return r, g, b


def main(size=(200, 100), mode='math', chrNumber=6, bgcolor=(255, 255, 255), font_size=48, font_path='./simhei.ttf'):
    """
    定义图片大小，验证码长度，背景颜色
    :param font_size:
    :param font_path:
    :param mode:
    :param size:
    :param chrNumber:
    :param bgcolor:
    :return:
    """
    # 创建空白图像和绘图对象
    image_tmp = Image.new('RGB', size, bgcolor)
    draw = ImageDraw.Draw(image_tmp)

    if mode == 'math':
        text0, result = math_challenge()
    else:
        text0 = selected_chrs(chrNumber)
        result = text0
    text = text0
    chrNumber = len(text)
    font = ImageFont.truetype(font_path, font_size)  # 选定一款系统字体
    width = draw.textlength(text, font)
    height = font_size
    if width + 2 * chrNumber > size[0] or height > size[1]:
        print('Size Error!')
        return False

    # 绘制字符串
    startX = 0
    width_eachchr = width // chrNumber  # 计算每个字符宽度
    for i in range(chrNumber):
        startX += width_eachchr + 1
        position = (startX, (size[1] - height) // 2+ randint(-10, 10))  # 字符坐标, Y坐标上下浮动
        draw.text(xy=position, text=text[i], font=font, fill=get_color())  # 绘制函数

    # 对像素位置进行微调，实现验证码扭曲效果
    img_final = Image.new('RGB', size, bgcolor)
    pixels_final = img_final.load()
    pixels_tmp = image_tmp.load()
    for y in range(size[1]):
        offset = randint(-1, 0)  # randint()相当于闭区间[x,y]
        for x in range(size[0]):
            newx = x + offset  # 像素微调
            if newx >= size[0]:
                newx = size[0] - 1
            elif newx < 0:
                newx = 0
            pixels_final[newx, y] = pixels_tmp[x, y]

    # 绘制随机颜色随机位置的干扰像素
    draw = ImageDraw.Draw(img_final)
    for i in range(int(size[0] * size[1] * 0.03)):  # 7%密度的干扰像素
        draw.point((randrange(size[0]), randrange(size[1])), fill=get_color())  # randrange取值范围是左开右闭

    # 绘制随机干扰线，这里设置为8条
    for i in range(3):
        start = (0, randrange(size[1]))
        end = (size[0], randrange(size[1]))
        draw.line([start, end], fill=get_color(), width=1)

    # 绘制随机弧线
    for i in range(3):
        start = (-50, -50)  # 起始位置在外边看起来才会像弧线
        end = (size[0] + 10, randint(0, size[1] + 10))
        draw.arc(start + end, 0, 360, fill=get_color())

    return img_final, text0, result


def get_captcha(size=(200, 100), mode='math', chrNumber=6, bgcolor=(255, 255, 255), font_size=48):
    img, code, res = main()
    # img.save('captcha.png')
    bIo = BytesIO()
    img.save(bIo, format='PNG')
    ig = bIo.getvalue()
    data = base64.b64encode(ig)
    data = data.decode('utf-8')
    return data, code, res


if __name__ == '__main__':

    im, code, res = get_captcha()
    print(code, res)























